package cn.demoncat.util.sms.yuntongxun;

import cn.demoncat.util.lang.LogUtil;
import cn.demoncat.util.lang.StringUtil;
import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.lang.entity.ListStr;
import cn.demoncat.util.lang.entity.Result;
import cn.demoncat.util.lang.entity.SmsData;
import cn.demoncat.util.lang.msg.SmsLogMsg;
import cn.demoncat.util.lang.msg.SmsMsg;
import cn.demoncat.util.sms.SmsInterface;
import com.cloopen.rest.sdk.CCPRestSmsSDK;
import org.slf4j.Logger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 容联云通讯短信服务
 * 
 * @author 延晓磊
 *
 * @since 2019年1月9日
 */
@Component("smsYuntongxunUtil")
public final class SmsYuntongxunUtil implements SmsInterface{

	// 服务端地址
	private static final String SERVER_URL = "app.cloopen.com";
	private static final String SERVER_PORT = "8883";
	
	// 状态码-成功
	// http://doc.yuntongxun.com/p/5a5857203b8496dd00dd2b3d
	private static final String CODE_OK = "000000";
	// 发送超限
	private static final List<String> CODE_LIMIT = ListStr.getInstance("160039", "160040", "160041", "160210");
	// 发送频繁
	private static final List<String> CODE_OFTEN = ListStr.getInstance("160038");

	private static final Logger LOG = LogUtil.get(SmsYuntongxunUtil.class);
	
	// 容联配置
	@Resource
	private SmsYuntongxunProperties smsYuntongxunProperties;
	// 容联手机号数量限制
	public static final int MAX_PHONES = 200;
			
	/**
	 * 发送短信
	 * 
	 * 注：如果手机号超过200条，会批量发送，但只返回最后一次发送的响应结果，这样就与服务端的流水号会不一致
	 * 
	 * @param data		请求数据（引用传值）
	 * 
	 * @return Result	处理后的结果[500请求失败,400发送出错,200发送成功]
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年1月9日
	 */
	@Override
	public Result send(SmsData data) {
		LOG.info(SmsLogMsg.SEND_SMS, data.getAppName(), data.getTemplateId(), data.getPhone());
		
		// 清空回执编号、状态、消息
		data.setBizId(StringConstant.EMPTY);
		data.setCode(StringConstant.EMPTY);
		data.setMessage(StringConstant.EMPTY);
				
		//初始化SDK
		CCPRestSmsSDK restAPI = new CCPRestSmsSDK();
		restAPI.init(SERVER_URL, SERVER_PORT);
		restAPI.setAppId(smsYuntongxunProperties.getApp());
		restAPI.setAccount(smsYuntongxunProperties.getAccount(), smsYuntongxunProperties.getPassword());
		// 发送短信
		if (data.getPhones().size() < MAX_PHONES) {
			// 单次
			return send(data, data.getPhone(), restAPI);
		}else {
			// 多次
			int size = MAX_PHONES / 2;
			int times = data.getPhones().size() % size == 0 ? data.getPhones().size()/size : data.getPhones().size()/size + 1;
			ArrayList<String> phones = new ArrayList<>(data.getPhones());
			String phone;
			Result result = null;
			for (int i = 0;  i < times; i++) {
				// 分批手机号
				if (i == times -1) {
					phone = StringUtil.join(phones.subList(i*size, phones.size()));
				}else {
					phone = StringUtil.join(phones.subList(i*size, (i+1)*size));
				}
				// 发送
				result = send(data, phone, restAPI);
				if (!Result.isSuccess(result)) {
					// 出错停止
					return result;
				}
			}
			return result;
		}
	}

	/**
	 * 发送短信
	 * 
	 * @param data
	 * @param phone
	 * @param restAPI
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2019年7月16日
	 */
	private static Result send(SmsData data, String phone, CCPRestSmsSDK restAPI) {
		Map<String, String> response;
		try {
			// 发送短信
			response = restAPI.sendTemplateSMS(phone, data.getTemplate(), data.getParam());
		} catch (Exception e) {
			// 请求失败
			LOG.error(SmsLogMsg.SEND_SMS_ERROR_BEFORE, data.getAppName(), data.getTemplateId(), data.getPhone(), e);
			data.setMessage(e.getMessage());
			return Result.FAIL;
		}
		// 结果校验
		String code = response.get("code");
		data.setCode(code);
		if (CODE_OK.equals(code)) {
			data.setBizId(response.get("sid"));
			return Result.SUCCESS;
		}else {
			data.setMessage(response.get("msg"));
			if (CODE_OFTEN.contains(code)) {
				// 发送频繁
				log(true, data, response);
				return Result.error(SmsMsg.SMS_SEND_ERROR_OFTEN);
			}else if (CODE_LIMIT.contains(code)) {
				// 发送超限
				log(true, data, response);
				return Result.error(SmsMsg.SMS_SEND_ERROR_LIMIT);
			}else{
				// 其它
				log(false, data, response);
				return Result.error(SmsMsg.SMS_SEND_ERROR);
			}
		}
	}

	/**
	 * 错误日志
	 *
	 * @param isWarn
	 * @param data
	 * @param response
	 */
	private static void log(boolean isWarn, SmsData data, Map<String, String> response){
		if (isWarn) {
			LOG.warn(SmsLogMsg.SEND_SMS_ERROR_AFTER, data.getAppName(), data.getTemplateId(), data.getPhone(), data.getParamText(), response);
		}else{
			LOG.error(SmsLogMsg.SEND_SMS_ERROR_AFTER, data.getAppName(), data.getTemplateId(), data.getPhone(), data.getParamText(), response);
		}
	}
	
}
